package com.kmxd.ams.app.system;

import static com.kmxd.ams.core.common.constant.RoleConst.ROLE_DEF_USER_CODE;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.kmxd.ams.app.system.command.InitCropCmd;
import com.kmxd.ams.client.es.IDocumentEsSvc;
import com.kmxd.ams.client.system.*;
import com.kmxd.ams.client.system.dto.*;
import com.kmxd.ams.client.system.vo.*;
import com.kmxd.ams.core.common.bo.LoginUser;
import com.kmxd.ams.core.common.bo.SysRoleBO;
import com.kmxd.ams.core.common.constant.ConfigConst;
import com.kmxd.ams.core.common.constant.Constants;
import com.kmxd.ams.core.common.constant.ErrorCode;
import com.kmxd.ams.core.common.enums.MessageSendTypeEnum;
import com.kmxd.ams.core.common.enums.MessageTypeEnum;
import com.kmxd.ams.core.common.enums.YesNoEnum;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.util.ConvertUtil;
import com.kmxd.ams.core.util.IdUtil;
import com.kmxd.ams.core.util.SecurityUtil;
import com.kmxd.ams.infra.arrange.base.BaseBO;
import com.kmxd.ams.infra.system.entity.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 系统公共接口
 *
 * @author ZuoLG
 */
@Slf4j
@Service
@AllArgsConstructor
public class SysCommonSvcImpl implements ISysCommonSvc {

  private ISysConfigSvc sysConfigSvc;
  private ISysRoleSvc sysRoleSvc;
  private ISysCropSvc sysCropSvc;
  private ISysFondsSvc sysFondsSvc;
  private ISysDeptSvc sysDeptSvc;
  private ISysUserSvc sysUserSvc;
  private ISysMenuSvc sysMenuSvc;
  private ISysMessagesSvc sysMessagesSvc;
  private InitCropCmd initCropCmd;
  private RedisTemplate redisTemplate;

  @Transactional(rollbackFor = Exception.class)
  @Override
  public void init(SysInitDTO req) {
    // 1、初始化单位
    // 2、初始化3元角色
    // sysInitValue为空或者值为false 未初始化
    SysConfig sysConfig = sysConfigSvc.getConfigValueByKey(ConfigConst.SYSTEM_INIT);
    if (ObjectUtil.isNull(sysConfig)) {
      sysConfig = new SysConfig();
      sysConfig.setName("系统初始化");
    }
    if (StrUtil.equals(sysConfig.getContent(), YesNoEnum.YES.getCode())) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "当前系统已经初始化，请勿重复初始化!");
    } else {
      // 初始化信息
      SysCrop sysCrop = sysCropSvc.getById(Constants.DEFAULT_CROP_ID);
      if (ObjectUtil.isEmpty(sysCrop)) {
        sysCrop = new SysCrop();
      }
      sysCrop.setId(Constants.DEFAULT_CROP_ID);
      sysCrop.setCode(String.valueOf(Constants.DEFAULT_CROP_ID));
      sysCrop.setName(req.getName());
      sysCrop.setShortName(req.getShortName());
      sysCrop.setParentId(0L);
      sysCrop.setPathCode(sysCrop.getParentId().toString());
      sysCrop.setDivide(0L);
      sysCrop.setRemarks(req.getShortName());
      sysCrop.setParentId(null);
      sysCrop.setLevel(1);
      sysCrop.setSort(0);
      sysCrop.setSubCropNum(ObjectUtil.isEmpty(req.getSubCropNum()) ? 125L : req.getSubCropNum());

      sysCropSvc.saveOrUpdate(sysCrop);
      // 初始化单位相关信息
      SysCropAddDTO cropAddDTO = BeanUtil.copyProperties(req, SysCropAddDTO.class);
      cropAddDTO.setDefDeptId(Constants.DEFAULT_CROP_ID * 8);
      initCropCmd.initCrop(sysCrop, cropAddDTO);

      sysConfig.setContent(YesNoEnum.YES.getCode());
      sysConfig.setCode(ConfigConst.SYSTEM_INIT);
      sysConfig.setType(0L);
      sysConfig.setStatus(0);
      sysConfig.setSort(1);
      sysConfigSvc.saveOrUpdate(sysConfig);
      sysConfigSvc.clearAllCache();

      // 系统初始化成功
      CompletableFuture.runAsync(
          () -> {
            try {
              SysMessagesAddDTO messagesAddDTO = new SysMessagesAddDTO();
              messagesAddDTO.setTitle("系统初始化提示！");
              messagesAddDTO.setMsgContent(
                  StrUtil.format(
                      "系统初始化成功！</br>单位名称:【{}】</br>单位编码:【{}】</br>单位管理员:【{}】",
                      req.getName(),
                      req.getFondsCode(),
                      req.getAdminUser()));
              // 通知
              SysUserVO user =
                  Optional.ofNullable(sysUserSvc.getUserByAccount(req.getAdminUser()))
                      .orElse(new SysUserVO());
              messagesAddDTO.setMsgCategory(MessageTypeEnum.NOTICE.getType());
              messagesAddDTO.setReceiver(String.valueOf(user.getId()));
              messagesAddDTO.setSendType(MessageSendTypeEnum.USER.getType());
              messagesAddDTO.setComId(Constants.DEFAULT_CROP_ID);
              sysMessagesSvc.add(messagesAddDTO);
              // 删除es索引
              IDocumentEsSvc esSvc = SpringUtil.getBean(IDocumentEsSvc.class);
              esSvc.deleteAll();
              // 初始化时清空所有缓存，清除相关缓存信息
              Set<String> keys = redisTemplate.keys("*");
              for (String key : keys) {
                redisTemplate.delete(key);
              }
            } catch (Exception e) {
              log.error(e.getMessage(), e);
            }
          });
    }
  }

  @Override
  public boolean initSystemStatus() {
    sysConfigSvc.clearAllCache();
    SysConfig sysConfig = sysConfigSvc.getConfigValueByKey(ConfigConst.SYSTEM_INIT);
    return ObjectUtil.isNotEmpty(sysConfig)
      && StrUtil.equals(sysConfig.getContent(), YesNoEnum.YES.getCode());
  }

  @Override
  public List<SysCropVO> getCropByDeptIds(String deptIds) {
    List<SysDeptVO> depts = getDeptByDeptIds(deptIds);
    // 获取单位ids
    Set<Long> comIds = depts.stream().map(item -> item.getComId()).collect(Collectors.toSet());
    if (comIds.isEmpty()) {
      throw BizTipException.instance(ErrorCode.EXCEPTION, StrUtil.format("未找到单位信息，请确定单位是否已经移除！"));
    }
    LambdaQueryWrapper<SysCrop> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.in(SysCrop::getId, comIds);
    List<SysCrop> list = sysCropSvc.list(queryWrapper);
    if (list.isEmpty()) {
      throw BizTipException.instance(ErrorCode.EXCEPTION, StrUtil.format("未找到单位信息，请确定单位是否已经移除！"));
    }
    return ConvertUtil.toList(list, SysCropVO.class);
  }

  @Override
  public SysFondsVO getDefFonds(long cropId) {
    List<SysFonds> list = sysFondsSvc.getDefFonds(cropId);
    SysFonds sysFonds = list.size() > 0 ? list.get(0) : new SysFonds();
    return ConvertUtil.toBean(sysFonds, SysFondsVO.class);
  }

  @Override
  public List<SysFondsListVO> getCropFonds(long cropId) {
    List<SysFonds> list = sysFondsSvc.getDefFonds(cropId);
    return ConvertUtil.toList(list, SysFondsListVO.class);
  }

  @Override
  public List<SysDeptVO> getDeptByDeptIds(String deptIds) {
    LambdaQueryWrapper<SysDept> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.in(SysDept::getId, IdUtil.split(deptIds));
    List<SysDept> list = sysDeptSvc.list(queryWrapper);
    if (list.isEmpty()) {
      throw BizTipException.instance(ErrorCode.EXCEPTION, StrUtil.format("未找到归属部门，请检查用户配置是否正确！"));
    }
    return ConvertUtil.toList(list, SysDeptVO.class);
  }

  @Override
  public List<UserLoginAuthVO> getUserByAuth(long userId) {
    // 查询用户
    SysUser sysUser = sysUserSvc.getById(userId);
    List<SysCropVO> crops = getCropByDeptIds(sysUser.getDeptId().toString());
    List<SysDeptVO> depts = getDeptByDeptIds(sysUser.getDeptId().toString());
    List<SysRole> sysRoleList = sysRoleSvc.listSysRoleByUserId(userId);
    List<UserLoginAuthVO> userLoginAuth = Lists.newArrayList();
    // todo逻辑有问题，此角色不在这个单位下
    crops.forEach(
        crop -> {
          UserLoginAuthVO userLoginAuthVO = new UserLoginAuthVO();
          userLoginAuthVO.setId(crop.getId().toString());
          userLoginAuthVO.setName(crop.getName());
          depts.forEach(
              dept -> {
                if (ObjectUtil.equals(dept.getComId(), crop.getId())) {
                  userLoginAuthVO.setId(userLoginAuthVO.getId() + "-" + dept.getId().toString());
                  userLoginAuthVO.setName(userLoginAuthVO.getName() + "-" + dept.getName());
                }
                sysRoleList.forEach(
                    role -> {
                      if (ObjectUtil.equals(role.getComId(), crop.getId())) {
                        userLoginAuthVO.setId(
                            userLoginAuthVO.getId() + "-" + role.getId().toString());
                        userLoginAuthVO.setName(
                            userLoginAuthVO.getName() + "-" + role.getRoleName());
                      }
                      userLoginAuth.add(userLoginAuthVO);
                    });
              });
        });
    return userLoginAuth;
  }

  @Override
  public LoginUser setLoginUserAuth(String authIdStr, LoginUser loginUser) {
    // 规则 【单位-部门-角色】
    List<Long> authId =
        Arrays.stream(authIdStr.split("-")).map(Long::parseLong).collect(Collectors.toList());
    if (authId.size() != 3) {
      log.info("当前用户权限异常:{}", authId);
      return loginUser;
    }
    // 设置单位，全宗，角色
    SysCrop sysCrop = sysCropSvc.getById(authId.get(0));
    SysFondsVO sysFonds = getDefFonds(authId.get(0));
    SysRole sysRole = sysRoleSvc.getById(authId.get(2));

    if (ObjectUtil.isNotNull(sysCrop) && ObjectUtil.isNotNull(sysCrop.getId())) {
      loginUser.setCropId(sysCrop.getId());
      loginUser.setCropName(sysCrop.getName());
      loginUser.setUserCropId(sysCrop.getId());
    }
    if (ObjectUtil.isNotNull(sysFonds) && ObjectUtil.isNotNull(sysFonds.getId())) {
      loginUser.setFondsId(sysFonds.getId());
      loginUser.setFondsName(sysFonds.getName());
      loginUser.setFondsCode(sysFonds.getCode());
      loginUser.setIndexNum(sysFonds.getAutoIndex());
    }
    if (ObjectUtil.isNotNull(sysRole) && ObjectUtil.isNotNull(sysRole.getId())) {
      loginUser.setRoleId(sysRole.getId());
      loginUser.setRoleType(sysRole.getRoleType());
      loginUser.setRoleName(sysRole.getRoleName());
      loginUser.setUserRoleId(sysRole.getId());
    }

    return loginUser;
  }

  @Override
  public LoginUser switchUnit(SwitchUnitDTO req) {
    // 设置单位
    SysCrop sysCrop = sysCropSvc.getById(req.getUnitId());
    if (ObjectUtil.isEmpty(sysCrop)) {
      throw BizTipException.instance(ErrorCode.EXCEPTION, "对不起，找不到任何归属单位");
    }
    List<SysFonds> fonds = sysFondsSvc.getDefFonds(sysCrop.getId());
    if (fonds.isEmpty()) {
      throw BizTipException.instance(ErrorCode.EXCEPTION, "对不起，当前单位未找到默认全宗！");
    }
    // 找到单位的默认用户角色，配置相应权限
    SysRole sysRole = sysRoleSvc.selectByCode(StrUtil.format(ROLE_DEF_USER_CODE, sysCrop.getId()));
    if (ObjectUtil.isEmpty(sysRole)) {
      throw BizTipException.instance(ErrorCode.EXCEPTION, "对不起，未对外开放相应权限！");
    }
    Set<String> permissions = sysMenuSvc.getPermissionsByRoleId(sysRole.getId());
    setSwitchObj(sysCrop, fonds.get(0), sysRole, permissions);
    return SecurityUtil.getLoginUser();
  }

  @Override
  public LoginUser switchFonds(SwitchFondsDTO req) {
    // 设置全宗
    SysFonds sysFonds = sysFondsSvc.getById(req.getFondsId());
    if (ObjectUtil.isEmpty(sysFonds)) {
      throw BizTipException.instance(ErrorCode.EXCEPTION, "对不起，当前单位未找到默认全宗！");
    }
    // 设置单位
    SysCrop sysCrop = sysCropSvc.getById(sysFonds.getComId());
    if (ObjectUtil.isEmpty(sysCrop)) {
      throw BizTipException.instance(ErrorCode.EXCEPTION, "对不起，找不到任何归属单位");
    }
    setSwitchObj(sysCrop, sysFonds, null, null);
    // 查找单位下的普通用户角色进行权限切换
    return SecurityUtil.getLoginUser();
  }

  @Override
  public LoginUser backCrop(BaseBO req) {
    LoginUser loginUser = SecurityUtil.getLoginUser();
    // 设置单位
    SysCrop sysCrop = sysCropSvc.getById(loginUser.getUserCropId());
    if (ObjectUtil.isEmpty(sysCrop)) {
      throw BizTipException.instance(ErrorCode.EXCEPTION, "对不起，找不到任何归属单位");
    }
    List<SysFonds> fonds = sysFondsSvc.getDefFonds(sysCrop.getId());
    if (fonds.isEmpty()) {
      throw BizTipException.instance(ErrorCode.EXCEPTION, "对不起，当前单位未找到默认全宗！");
    }
    // 找到单位的默认用户角色，配置相应权限
    SysRole sysRole = sysRoleSvc.getById(loginUser.getUserRoleId());
    if (ObjectUtil.isEmpty(sysRole)) {
      throw BizTipException.instance(ErrorCode.EXCEPTION, "对不起，权限对象获取异常！");
    }
    Set<String> permissions = Sets.newHashSet();
    if (SecurityUtil.isRootGroup()) {
      permissions.add(Constants.ALL_PERMISSION);
    } else {
      permissions = sysMenuSvc.getPermissionsByRoleId(sysRole.getId());
    }
    setSwitchObj(sysCrop, fonds.get(0), sysRole, permissions);

    return SecurityUtil.getLoginUser();
  }

  /**
   * 设置切换对象
   *
   * @param sysCrop
   * @param sysFonds
   * @param sysRole
   */
  public void setSwitchObj(
      SysCrop sysCrop, SysFonds sysFonds, SysRole sysRole, Set<String> permissions) {
    LoginUser loginUser = SecurityUtil.getLoginUser();
    if (ObjectUtil.isNotNull(sysCrop) && ObjectUtil.isNotNull(sysCrop.getId())) {
      Objects.requireNonNull(loginUser).setCropId(sysCrop.getId());
      loginUser.setCropName(sysCrop.getName());
    }
    if (ObjectUtil.isNotNull(sysFonds) && ObjectUtil.isNotNull(sysFonds.getId())) {
      Objects.requireNonNull(loginUser).setFondsId(sysFonds.getId());
      loginUser.setFondsName(sysFonds.getName());
      loginUser.setFondsCode(sysFonds.getCode());
      loginUser.setIndexNum(sysFonds.getAutoIndex());
    }
    if (ObjectUtil.isNotNull(sysRole) && ObjectUtil.isNotNull(sysRole.getId())) {
      Objects.requireNonNull(loginUser).setRoleId(sysRole.getId());
      loginUser.setRoleName(sysRole.getRoleName());
      loginUser.setRoleType(sysRole.getRoleType());

      // 查询角色列表 -- 冗余数据，方便使用
      List<SysRoleBO> roleInfoVOList = Lists.newArrayList();
      roleInfoVOList.add(BeanUtil.copyProperties(sysRole, SysRoleBO.class));
      loginUser.setRoles(roleInfoVOList);
    }
    if (ObjectUtil.isNotNull(permissions)) {
      loginUser.setPermissions(permissions);
    }
    StpUtil.getTokenSession().set(Constants.LOGIN_USER_KEY, loginUser);
  }
}
